home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / _archvrs / unix / tar_110.lha / tar-1.10 / gnu.c < prev    next >
C/C++ Source or Header  |  1991-05-19  |  12KB  |  631 lines

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <ctype.h>
  5. #include <errno.h>
  6.  
  7. #ifdef BSD42
  8. #include <sys/dir.h>
  9. #else
  10. #ifdef __MSDOS__
  11. #include "msd_dir.h"
  12. #else
  13. #ifdef USG
  14. #ifdef NDIR
  15. #include <ndir.h>
  16. #else
  17. #include <dirent.h>
  18. #endif
  19. #ifndef DIRECT
  20. #define direct dirent
  21. #endif
  22. #define DP_NAMELEN(x) strlen((x)->d_name)
  23. #else
  24. /*
  25.  * FIXME: On other systems there is no standard place for the header file
  26.  * for the portable directory access routines.  Change the #include line
  27.  * below to bring it in from wherever it is.
  28.  */
  29. #include "ndir.h"
  30. #endif
  31. #endif
  32. #endif
  33.  
  34. #ifndef DP_NAMELEN
  35. #define DP_NAMELEN(x)    (x)->d_namlen
  36. #endif
  37.  
  38. #ifndef MAXPATHLEN
  39. #define MAXPATHLEN 1024
  40. #endif
  41.  
  42. /*
  43.  * If there are no symbolic links, there is no lstat().  Use stat().
  44.  */
  45. #ifndef S_IFLNK
  46. #define lstat stat
  47. #endif
  48.  
  49. #ifdef __STDC__
  50. #define VOIDSTAR void *
  51. #else
  52. #define VOIDSTAR char *
  53. #endif
  54. extern VOIDSTAR ck_malloc();
  55. extern VOIDSTAR ck_realloc();
  56.  
  57. #ifndef S_IFLNK
  58. #define lstat stat
  59. #endif
  60.  
  61. extern VOIDSTAR malloc();
  62.  
  63. #include "tar.h"
  64.  
  65. extern time_t new_time;
  66. extern FILE *msg_file;
  67.  
  68. extern VOIDSTAR init_buffer();
  69. extern char *get_buffer();
  70. extern void add_buffer();
  71. extern void flush_buffer();
  72.  
  73. extern char *new_name();
  74.  
  75. static void add_dir_name();
  76.  
  77. struct dirname {
  78.     struct dirname *next;
  79.     char *name;
  80.     char *dir_text;
  81.     int dev;
  82.     int ino;
  83.     int allnew;
  84. };
  85. static struct dirname *dir_list;
  86. static time_t this_time;
  87.  
  88. void
  89. add_dir(name,dev,ino,text)
  90. char *name;
  91. char *text;
  92. {
  93.     struct dirname *dp;
  94.  
  95.     dp=(struct dirname *)malloc(sizeof(struct dirname));
  96.     if(!dp)
  97.         abort();
  98.     dp->next=dir_list;
  99.     dir_list=dp;
  100.     dp->dev=dev;
  101.     dp->ino=ino;
  102.     dp->name=malloc(strlen(name)+1);
  103.     strcpy(dp->name,name);
  104.     dp->dir_text=text;
  105.     dp->allnew=0;
  106. }
  107.  
  108. void
  109. read_dir_file()
  110. {
  111.     int dev;
  112.     int ino;
  113.     char *strp;
  114.     FILE *fp;
  115.     char buf[512];
  116.     extern int errno;
  117.     static char path[MAXPATHLEN];
  118.  
  119.     time(&this_time);
  120.     if(gnu_dumpfile[0]!='/') {
  121. #if defined(MSDOS) || defined(USG)
  122.             int getcwd();
  123.  
  124.             if(!getcwd(path,MAXPATHLEN))
  125.                 msg("Couldn't get current directory.");
  126.                 exit(EX_SYSTEM);
  127. #else
  128.             char *getwd();
  129.  
  130.             if(!getwd(path)) {
  131.                 msg("Couldn't get current directory: %s",path);
  132.                 exit(EX_SYSTEM);
  133.             }
  134. #endif
  135.         /* If this doesn't fit, we're in serious trouble */
  136.         strcat(path,"/");
  137.         strcat(path,gnu_dumpfile);
  138.         gnu_dumpfile=path;
  139.     }
  140.     fp=fopen(gnu_dumpfile,"r");
  141.     if(fp==0 && errno!=ENOENT) {
  142.         msg_perror("Can't open %s",gnu_dumpfile);
  143.         return;
  144.     }
  145.     if(!fp)
  146.         return;
  147.     fgets(buf,sizeof(buf),fp);
  148.     if(!f_new_files) {
  149.         f_new_files++;
  150.         new_time=atol(buf);
  151.     }
  152.     while(fgets(buf,sizeof(buf),fp)) {
  153.         strp= &buf[strlen(buf)];
  154.         if(strp[-1]=='\n')
  155.             strp[-1]='\0';
  156.         strp=buf;
  157.         dev=atol(strp);
  158.         while(isdigit(*strp))
  159.             strp++;
  160.         ino=atol(strp);
  161.         while(isspace(*strp))
  162.             strp++;
  163.         while(isdigit(*strp))
  164.             strp++;
  165.         strp++;
  166.         add_dir(un_quote_string(strp),dev,ino,(char *)0);
  167.     }
  168.     fclose(fp);
  169. }
  170.  
  171. void
  172. write_dir_file()
  173. {
  174.     FILE *fp;
  175.     struct dirname *dp;
  176.     char *str;
  177.     extern char *quote_copy_string();
  178.  
  179.     fp=fopen(gnu_dumpfile,"w");
  180.     if(fp==0) {
  181.         msg_perror("Can't write to %s",gnu_dumpfile);
  182.         return;
  183.     }
  184.     fprintf(fp,"%lu\n",this_time);
  185.     for(dp=dir_list;dp;dp=dp->next) {
  186.         if(!dp->dir_text)
  187.             continue;
  188.         str=quote_copy_string(dp->name);
  189.         if(str) {
  190.             fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,str);
  191.             free(str);
  192.         } else
  193.             fprintf(fp,"%u %u %s\n",dp->dev,dp->ino,dp->name);
  194.     }
  195.     fclose(fp);
  196. }
  197.  
  198. struct dirname *
  199. get_dir(name)
  200. char *name;
  201. {
  202.     struct dirname *dp;
  203.  
  204.     for(dp=dir_list;dp;dp=dp->next) {
  205.         if(!strcmp(dp->name,name))
  206.             return dp;
  207.     }
  208.     return 0;
  209. }
  210.  
  211.  
  212. /* Collect all the names from argv[] (or whatever), then expand them into
  213.    a directory tree, and put all the directories at the beginning. */
  214. collect_and_sort_names()
  215. {
  216.     struct name *n,*n_next;
  217.     int num_names;
  218.     struct stat statbuf;
  219.     int name_cmp();
  220.     char *merge_sort();
  221.  
  222.     name_gather();
  223.  
  224.     if(gnu_dumpfile)
  225.         read_dir_file();
  226.     if(!namelist) addname(".");
  227.     for(n=namelist;n;n=n_next) {
  228.         n_next=n->next;
  229.         if(n->found || n->dir_contents)
  230.             continue;
  231.         if(n->regexp)        /* FIXME just skip regexps for now */
  232.             continue;
  233.         if(n->change_dir)
  234.             if(chdir(n->change_dir)<0) {
  235.                 msg_perror("can't chdir to %s",n->change_dir);
  236.                 continue;
  237.             }
  238.  
  239. #ifdef AIX
  240.         if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN|STX_LINK))
  241. #else
  242.         if(lstat(n->name,&statbuf)<0) {
  243. #endif /* AIX */
  244.             msg_perror("can't stat %s",n->name);
  245.             continue;
  246.         }
  247.         if((statbuf.st_mode&S_IFMT)==S_IFDIR) {
  248.             n->found++;
  249.             add_dir_name(n->name,statbuf.st_dev);
  250.         }
  251.     }
  252.  
  253.     num_names=0;
  254.     for(n=namelist;n;n=n->next)
  255.         num_names++;
  256.     namelist=(struct name *)merge_sort((VOIDSTAR)namelist,num_names,(char *)(&(namelist->next))-(char *)namelist,name_cmp);
  257.  
  258.     for(n=namelist;n;n=n->next) {
  259.         n->found=0;
  260.     }
  261.     /* if(gnu_dumpfile)
  262.         write_dir_file(gnu_dumpfile); */
  263. }
  264.  
  265. int
  266. name_cmp(n1,n2)
  267. struct name *n1,*n2;
  268. {
  269.     if(n1->found) {
  270.         if(n2->found)
  271.             return strcmp(n1->name,n2->name);
  272.         else
  273.             return -1;
  274.     } else if(n2->found)
  275.         return 1;
  276.     else
  277.         return strcmp(n1->name,n2->name);
  278. }
  279.  
  280. int
  281. dirent_cmp(p1,p2)
  282. char **p1,**p2;
  283. {
  284.     char *frst,*scnd;
  285.  
  286.     frst= (*p1)+1;
  287.     scnd= (*p2)+1;
  288.  
  289.     return strcmp(frst,scnd);
  290. }
  291.  
  292. char *
  293. get_dir_contents(p,device)
  294. char *p;
  295. int device;
  296. {
  297.     DIR *dirp;
  298.     register struct direct *d;
  299.     char *new_buf;
  300.     char *namebuf;
  301.     int bufsiz;
  302.     int len;
  303.     VOIDSTAR the_buffer;
  304.     char *buf;
  305.     int n_strs;
  306.     int n_size;
  307.     char *p_buf;
  308.     char **vec,**p_vec;
  309.  
  310.     extern int errno;
  311.  
  312.     errno=0;
  313.     dirp=opendir(p);
  314.     bufsiz=strlen(p)+NAMSIZ;
  315.     namebuf=ck_malloc(bufsiz+2);
  316.     if(!dirp) {
  317.         if(errno)
  318.             msg_perror("can't open directory %s",p);
  319.         else
  320.             msg("error opening directory %s",p);
  321.         new_buf="\0\0\0\0";
  322.     } else {
  323.         struct dirname *dp;
  324.         int all_children;
  325.  
  326.         dp=get_dir(p);
  327.         all_children= dp ? dp->allnew : 0;
  328.         (void) strcpy(namebuf,p);
  329.         if(p[strlen(p)-1]!='/')
  330.             (void) strcat(namebuf,"/");
  331.         len=strlen(namebuf);
  332.  
  333.         the_buffer=init_buffer();
  334.         while(d=readdir(dirp)) {
  335.             struct stat hs;
  336.  
  337.             /* Skip . and .. */
  338.             if(is_dot_or_dotdot(d->d_name))
  339.                 continue;
  340.             if(DP_NAMELEN(d) + len >=bufsiz) {
  341.                 bufsiz+=NAMSIZ;
  342.                 namebuf=ck_realloc(namebuf,bufsiz+2);
  343.             }
  344.             (void) strcpy(namebuf+len,d->d_name);
  345. #ifdef AIX
  346.             if (0 != f_follow_links?
  347.                 statx(namebuf, &hs, STATSIZE, STX_HIDDEN):
  348.                 statx(namebuf, &hs, STATSIZE, STX_HIDDEN|STX_LINK))
  349. #else
  350.             if (0 != f_follow_links? stat(namebuf, &hs): lstat(namebuf, &hs))
  351. #endif
  352.             {
  353.                 msg_perror("can't stat %s",namebuf);
  354.                 continue;
  355.             }
  356.             if(   (f_local_filesys && device!=hs.st_dev)
  357.                || (f_exclude && check_exclude(namebuf)))
  358.                 add_buffer(the_buffer,"N",1);
  359. #ifdef AIX
  360.             else if (S_ISHIDDEN (hs.st_mode)) {
  361.                 add_buffer (the_buffer, "D", 1);
  362.                 strcat (d->d_name, "A");
  363.                 d->d_namlen++;
  364.             }    
  365. #endif /* AIX */
  366.             else if((hs.st_mode&S_IFMT)==S_IFDIR) {
  367.                 if(dp=get_dir(namebuf)) {
  368.                     if(   dp->dev!=hs.st_dev
  369.                         || dp->ino!=hs.st_ino) {
  370.                            if(f_verbose)
  371.                             msg("directory %s has been renamed.",namebuf);
  372.                         dp->allnew=1;
  373.                         dp->dev=hs.st_dev;
  374.                         dp->ino=hs.st_ino;
  375.                     }
  376.                     dp->dir_text="";
  377.                 } else {
  378.                     if(f_verbose)
  379.                         msg("Directory %s is new",namebuf);
  380.                     add_dir(namebuf,hs.st_dev,hs.st_ino,"");
  381.                     dp=get_dir(namebuf);
  382.                     dp->allnew=1;
  383.                 }
  384.                 if(all_children)
  385.                     dp->allnew=1;
  386.  
  387.                 add_buffer(the_buffer,"D",1);
  388.             } else if(   !all_children
  389.                    && f_new_files
  390.                  && new_time>hs.st_mtime
  391.                 && (   f_new_files>1
  392.                      || new_time>hs.st_ctime))
  393.                 add_buffer(the_buffer,"N",1);
  394.             else
  395.                 add_buffer(the_buffer,"Y",1);
  396.             add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1));
  397.         }
  398.         add_buffer(the_buffer,"\000\000",2);
  399.         closedir(dirp);
  400.  
  401.         /* Well, we've read in the contents of the dir, now sort them */
  402.         buf=get_buffer(the_buffer);
  403.         if(buf[0]=='\0') {
  404.             flush_buffer(the_buffer);
  405.             new_buf="\0\0\0\0";
  406.         } else {
  407.             n_strs=0;
  408.             for(p_buf=buf;*p_buf;) {
  409.                 int tmp;
  410.  
  411.                 tmp=strlen(p_buf)+1;
  412.                 n_strs++;
  413.                 p_buf+=tmp;
  414.             }
  415.             vec=(char **)malloc(sizeof(char *)*(n_strs+1));
  416.             for(p_vec=vec,p_buf=buf;*p_buf;p_buf+=strlen(p_buf)+1)
  417.                 *p_vec++= p_buf;
  418.             *p_vec= 0;
  419.             qsort((VOIDSTAR)vec,n_strs,sizeof(char *),dirent_cmp);
  420.             new_buf=(char *)malloc(p_buf-buf+2);
  421.             for(p_vec=vec,p_buf=new_buf;*p_vec;p_vec++) {
  422.                 char *p_tmp;
  423.  
  424.                 for(p_tmp= *p_vec;*p_buf++= *p_tmp++;)
  425.                     ;
  426.             }
  427.             *p_buf++='\0';
  428.             free(vec);
  429.             flush_buffer(the_buffer);
  430.         }
  431.     }
  432.     free(namebuf);
  433.     return new_buf;
  434. }
  435.  
  436. /* p is a directory.  Add all the files in P to the namelist.  If any of the
  437.    files is a directory, recurse on the subdirectory. . . */
  438. static void
  439. add_dir_name(p,device)
  440. char *p;
  441. int device;
  442. {
  443.     char *new_buf;
  444.     char *p_buf;
  445.  
  446.     char *namebuf;
  447.     int buflen;
  448.     register int len;
  449.     int sublen;
  450.  
  451.     VOIDSTAR the_buffer;
  452.  
  453.     char *buf;
  454.     char **vec,**p_vec;
  455.     int n_strs,n_size;
  456.  
  457.     struct name *n;
  458.  
  459.     int dirent_cmp();
  460.  
  461.     new_buf=get_dir_contents(p,device);
  462.  
  463.     for(n=namelist;n;n=n->next) {
  464.         if(!strcmp(n->name,p)) {
  465.             n->dir_contents = new_buf;
  466.             break;
  467.         }
  468.     }
  469.  
  470.     len=strlen(p);
  471.     buflen= NAMSIZ<=len ? len + NAMSIZ : NAMSIZ;
  472.     namebuf= ck_malloc(buflen+1);
  473.  
  474.     (void)strcpy(namebuf,p);
  475.     if(namebuf[len-1]!='/') {
  476.         namebuf[len++]='/';
  477.         namebuf[len]='\0';
  478.     }
  479.     for(p_buf=new_buf;*p_buf;p_buf+=sublen+1) {
  480.         sublen=strlen(p_buf);
  481.         if(*p_buf=='D') {
  482.             if(len+sublen>=buflen) {
  483.                 buflen+=NAMSIZ;
  484.                 namebuf= ck_realloc(namebuf,buflen+1);
  485.             }
  486.             (void)strcpy(namebuf+len,p_buf+1);
  487.             addname(namebuf);
  488.             add_dir_name(namebuf,device);
  489.         }
  490.     }
  491.     free(namebuf);
  492. }
  493.  
  494. /* Returns non-zero if p is . or ..   This could be a macro for speed. */
  495. is_dot_or_dotdot(p)
  496. char *p;
  497. {
  498.     return (p[0]=='.' && (p[1]=='\0' || (p[1]=='.' && p[2]=='\0')));
  499. }
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506. gnu_restore(skipcrud)
  507. int skipcrud;
  508. {
  509.     char *current_dir;
  510. /*    int current_dir_length; */
  511.  
  512.     char *archive_dir;
  513. /*    int archive_dir_length; */
  514.     VOIDSTAR the_buffer;
  515.     char    *p;
  516.     DIR    *dirp;
  517.     struct direct *d;
  518.     char *cur,*arc;
  519.     extern struct stat hstat;        /* Stat struct corresponding */
  520.     long size,copied;
  521.     char *from,*to;
  522.     extern union record *head;
  523.  
  524.     dirp=opendir(skipcrud+head->header.name);
  525.  
  526.     if(!dirp) {
  527.             /* The directory doesn't exist now.  It'll be created.
  528.                In any case, we don't have to delete any files out
  529.                of it */
  530.         skip_file((long)hstat.st_size);
  531.         return;
  532.     }
  533.  
  534.     the_buffer=init_buffer();
  535.     while(d=readdir(dirp)) {
  536.         if(is_dot_or_dotdot(d->d_name))
  537.             continue;
  538.  
  539.         add_buffer(the_buffer,d->d_name,(int)(DP_NAMELEN(d)+1));
  540.     }
  541.     closedir(dirp);
  542.     add_buffer(the_buffer,"",1);
  543.  
  544.     current_dir=get_buffer(the_buffer);
  545.     archive_dir=(char *)malloc(hstat.st_size);
  546.     if(archive_dir==0) {
  547.         msg("Can't allocate %d bytes for restore",hstat.st_size);
  548.         skip_file((long)hstat.st_size);
  549.         return;
  550.     }
  551.     to=archive_dir;
  552.     for(size=hstat.st_size;size>0;size-=copied) {
  553.         from=findrec()->charptr;
  554.         if(!from) {
  555.             msg("Unexpected EOF in archive\n");
  556.             break;
  557.         }
  558.         copied=endofrecs()->charptr - from;
  559.         if(copied>size)
  560.             copied=size;
  561.         bcopy((VOIDSTAR)from,(VOIDSTAR)to,(int)copied);
  562.         to+=copied;
  563.         userec((union record *)(from+copied-1));
  564.     }
  565.  
  566.     for(cur=current_dir;*cur;cur+=strlen(cur)+1) {
  567.         for(arc=archive_dir;*arc;arc+=strlen(arc)+1) {
  568.             arc++;
  569.             if(!strcmp(arc,cur))
  570.                 break;
  571.         }
  572.         if(*arc=='\0') {
  573.             p=new_name(skipcrud+head->header.name,cur);
  574.             if(f_confirm && !confirm("delete",p)) {
  575.                 free(p);
  576.                 continue;
  577.             }
  578.             if(f_verbose)
  579.                 fprintf(msg_file,"%s: deleting %s\n",tar,p);
  580.             if(recursively_delete(p)) {
  581.                 msg("%s: Error while deleting %s\n",tar,p);
  582.             }
  583.             free(p);
  584.         }
  585.  
  586.     }
  587.     flush_buffer(the_buffer);
  588.     free(archive_dir);
  589. }
  590.  
  591. recursively_delete(path)
  592. char *path;
  593. {
  594.     struct stat sbuf;
  595.     DIR *dirp;
  596.     struct direct *dp;
  597.     char *path_buf;
  598.     /* int path_len; */
  599.  
  600.  
  601.     if(lstat(path,&sbuf)<0)
  602.         return 1;
  603.     if((sbuf.st_mode &S_IFMT)==S_IFDIR) {
  604.  
  605.         /* path_len=strlen(path); */
  606.         dirp=opendir(path);
  607.         if(dirp==0)
  608.             return 1;
  609.         while(dp=readdir(dirp)) {
  610.             if(is_dot_or_dotdot(dp->d_name))
  611.                 continue;
  612.             path_buf=new_name(path,dp->d_name);
  613.             if(recursively_delete(path_buf)) {
  614.                 free(path_buf);
  615.                 closedir(dirp);
  616.                 return 1;
  617.             }
  618.             free(path_buf);
  619.         }
  620.         closedir(dirp);
  621.  
  622.         if(rmdir(path)<0)
  623.             return 1;
  624.         return 0;
  625.     }
  626.     if(unlink(path)<0)
  627.         return 1;
  628.     return 0;
  629. }
  630.  
  631.